Inside Macintosh: Files

Previous | Chapter Top | Chapter Contents | Next

Saving a File

There are several ways for a user to indicate that the current contents of a document should be saved (that is, written to disk). The user can choose the File menu commands Save or Save As, or the user can click the Save button in a dialog box that you display when the user attempts to close a "dirty" document (that is, a document whose contents have changed since the last time it was saved). You can handle the Save menu command quite easily, as illustrated in Listing 1-11 .

Listing 11 Handling the Save menu command

FUNCTION DoSaveCmd: OSErr;
VAR
    myWindow:       WindowPtr;                      {pointer to the front window}
    myData:         MyDocRecHnd;                    {handle to a document record}
    myErr:          OSErr;

BEGIN
    myWindow := FrontWindow;                        {get front window and its data}
    myData := MyDocRecHnd(GetWRefCon(myWindow));
    IF myData^^.fileRefNum <> 0 THEN                {if window has a file already}
        myErr := DoWriteFile(myWindow);             {then write contents to disk}
    ELSE
        myErr := DoSaveAsCmd;                       {else ask for a filename}
    DoSaveCmd := myErr;
END;

The DoSaveCmd function simply checks whether the frontmost window is already associated with a file. If so, then DoSaveCmd calls DoWriteFile to write the data to disk (using the "safe-save" process illustrated in the previous section). Otherwise, if no file exists for that window, DoSaveCmd calls DoSaveAsCmd . Listing 1-12 shows a way to define the DoSaveAsCmd function.

Listing 12 Handling the Save As menu command

FUNCTION DoSaveAsCmd: OSErr;
VAR
    myWindow:       WindowPtr;                  {pointer to the front window}
    myData:         MyDocRecHnd;                {handle to a document record}
    myReply:        StandardFileReply;
    myFile:         Integer;                    {file reference number}
    myErr:          OSErr;
BEGIN
    myWindow := FrontWindow;                    {get front window and its data}
    myData := MyDocRecHnd(GetWRefCon(myWindow));
    myErr := noErr;

    StandardPutFile('Save as:', 'Untitled', myReply);
    IF myReply.sfGood THEN                      {user saves file}
        BEGIN
            IF NOT myReply.sfReplacing THEN
                myErr := FSpCreate(myReply.sfFile, 'MYAP', 'TEXT',
                                             smSystemScript);
            IF myErr <> noErr THEN
                Exit(DoSaveAsCmd);
            myData^^.fileFSSpec := myReply.sfFile;

            IF myData^^.fileRefNum <> 0 THEN                {if window already has a file}
                myErr := FSClose(myData^^.fileRefNum);          {close it}

            {Create document's resource fork and copy Finder resources to it.}
            FSpCreateResFile(myData^^.fileFSSpec, 'MYAP', 'TEXT',
                                     smSystemScript);
            myErr := ResError;
            IF myErr = noErr THEN
                myFile := FSpOpenResFile(myData^^.fileFSSpec, fsRdWrPerm);
            IF myFile > 0 THEN                              {copy Finder resources}
                myErr := DoCopyResource('STR ', -16396, gAppsResFile, myFile)
            ELSE
                myErr := ResError;
            IF myErr = noErr THEN
                myErr := FSClose(myFile);                   {close the resource fork}

            {Open data fork and leave it open.}
            IF myErr = noErr THEN
                myErr := FSpOpenDF(myData^^.fileFSSpec, fsRdWrPerm, myFile);
            IF myErr = noErr THEN
                BEGIN
                    myData^^.fileRefNum := myFile;
                    SetWTitle(myWindow, myReply.sfFile.name);
                    myErr := DoWriteFile(myWindow);
                END;
            DoSaveAsCmd := myErr;
        END;
END;

The StandardPutFile procedure is similar to the StandardGetFile procedure discussed earlier in this chapter. It manages the user interface for the default Save dialog box, illustrated in Figure 1-8 .

Figure 8 The default Save dialog box

If the user clicks the New Folder button, the Standard File Package presents a subsidiary dialog box like the one shown in Figure 1-9 .

Figure 9 The new folder dialog box

If the user asks to save a file with a name that already exists at the specified location, the Standard File Package displays a subsidiary dialog box, like the one shown in Figure 1-10 , to verify that the new file should replace the existing file.

Figure 10 The name conflict dialog box

Note in Listing 1-12 that if the user is not replacing an existing file, the DoSaveAsCmd function creates a new file and records the new FSSpec record in the window's document record. Otherwise, if the user is replacing an existing file, DoSaveAsCmd simply records, in the window's document record, the FSSpec record returned by StandardGetFile .

When DoSaveAsCmd creates a new file, it also copies a resource from your application's resource fork to the resource fork of the newly created file. This resource (with ID -16396) identifies the name of your application. (For more details about this resource, see the chapter "Finder Interface" in Inside Macintosh: Macintosh Toolbox Essentials .) The DoSaveAsCmd function calls the application-defined routine DoCopyResource . Listing 1-13 shows a simple way to define the DoCopyResource function.

Listing 13 Copying a resource from one resource fork to another

FUNCTION DoCopyResource (theType: ResType; theID: Integer;
                                source: Integer; dest: Integer): OSErr;
VAR
    myHandle:       Handle;                                 {handle to resource to copy}
    myName:         Str255;                                 {name of resource to copy}
    myType:         ResType;                                {ignored; used for GetResInfo}
    myID:           Integer;                                {ignored; used for GetResInfo}
BEGIN
    UseResFile(source);                                     {set the source resource file}
    myHandle := GetResource(theType, theID);                {open the source resource}
    IF myHandle <> NIL THEN
        BEGIN
            GetResInfo(myHandle, myID, myType, myName);                 {get resource name}
            DetachResource(myHandle);                       {detach resource}
            UseResFile(dest);                               {set destination resource file}
            AddResource(myHandle, theType, theID, myName);
            IF ResError = noErr THEN
                WriteResource(myHandle);                    {write resource data}
            END;
        DoCopyResource := ResError;                             {return result code}
    ReleaseResource(myHandle);
END;

See the chapter "Resource Manager" in Inside Macintosh: More Macintosh Toolbox for details about the routines used in Listing 1-13 .


© 1997 Apple Computer, Inc.

Previous | Chapter Top | Chapter Contents | Next